﻿using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CoreShop.App.Scale
{
    public class SafeSerialPort : IDisposable
    {
        private SerialPort _serialPort;
        private ManualResetEvent _dataReceivedEvent = new ManualResetEvent(true);
        private bool _isDisposed = false;

        public SafeSerialPort(string portName, int baudRate)
        {
            _serialPort = new SerialPort(portName, baudRate);
            _serialPort.DataReceived += SerialPort_DataReceived;
            _serialPort.ErrorReceived += SerialPort_ErrorReceived;

            // 设置合理的超时时间
            _serialPort.ReadTimeout = 500;
            _serialPort.WriteTimeout = 500;
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                // 标记事件处理开始
                _dataReceivedEvent.Reset();

                // 快速处理数据，避免耗时操作
                if (_serialPort.IsOpen)
                {
                    int bytesToRead = _serialPort.BytesToRead;
                    byte[] buffer = new byte[bytesToRead];
                    _serialPort.Read(buffer, 0, bytesToRead);

                    // 通过Invoke将数据处理放到UI线程中
                    if (DataReceived != null)
                    {
                        DataReceived(this, new SerialDataEventArgs(buffer));
                    }
                }
            }
            catch (Exception ex)
            {
                // 处理异常
                if (ErrorReceived != null)
                {
                    ErrorReceived(this, new SerialErrorEventArgs(ex));
                }
            }
            finally
            {
                // 标记事件处理结束
                _dataReceivedEvent.Set();
            }
        }

        private void SerialPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            if (ErrorReceived != null)
            {
                ErrorReceived(this, new SerialErrorEventArgs(new Exception($"串口错误: {e.EventType}")));
            }
        }

        public void Open()
        {
            if (!_serialPort.IsOpen)
            {
                _serialPort.Open();
            }
        }

        public void Close()
        {
            try
            {
                // 停止接收数据
                _serialPort.DataReceived -= SerialPort_DataReceived;

                // 等待当前的数据接收事件处理完成
                if (_dataReceivedEvent.WaitOne(1000)) // 等待1秒
                {
                    if (_serialPort.IsOpen)
                    {
                        // 先禁用事件，再关闭串口
                        _serialPort.DtrEnable = false;
                        _serialPort.RtsEnable = false;

                        // 在后台线程中关闭串口
                        ThreadPool.QueueUserWorkItem(_ =>
                        {
                            try
                            {
                                _serialPort.Close();
                            }
                            catch (Exception ex)
                            {
                                if (ErrorReceived != null)
                                {
                                    ErrorReceived(this, new SerialErrorEventArgs(ex));
                                }
                            }
                        });
                    }
                }
                else
                {
                    // 超时处理
                    if (ErrorReceived != null)
                    {
                        ErrorReceived(this, new SerialErrorEventArgs(new TimeoutException("关闭串口时超时")));
                    }
                }
            }
            catch (Exception ex)
            {
                if (ErrorReceived != null)
                {
                    ErrorReceived(this, new SerialErrorEventArgs(ex));
                }
            }
        }

        public void Write(string data)
        {
            if (_serialPort.IsOpen)
            {
                _serialPort.Write(data);
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_isDisposed)
            {
                if (disposing)
                {
                    Close();
                    _dataReceivedEvent.Dispose();
                }

                _isDisposed = true;
            }
        }

        public event EventHandler<SerialDataEventArgs> DataReceived;
        public event EventHandler<SerialErrorEventArgs> ErrorReceived;
    }

    public class SerialDataEventArgs : EventArgs
    {
        public byte[] Data { get; private set; }
        public SerialDataEventArgs(byte[] data)
        {
            Data = data;
        }
    }

    public class SerialErrorEventArgs : EventArgs
    {
        public Exception Error { get; private set; }
        public SerialErrorEventArgs(Exception error)
        {
            Error = error;
        }
    }
}
